home *** CD-ROM | disk | FTP | other *** search
/ CICA 1993 April / CICA MS Windows - April 1993.iso / unzipped / programr / bcpp / cmmdlg / prn31_.pas < prev    next >
Pascal/Delphi Source File  |  1992-09-07  |  17KB  |  785 lines

  1. {$IFDEF WINDOWS}
  2.  
  3. {µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ}
  4. {   \\\                                    }
  5. {  -(j)-                                   }
  6. {    /juanca                               }
  7. {    ~                                     }
  8. {$D ⌐ ACASA 1989-1992, All rights reserved }
  9. {µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ}
  10.  
  11. {a tPrinter object, that knows about tUsrWin windows, and how to tell them to print }
  12. { also uses CommonDlgs for Print, and PrinterSetup }
  13.  
  14. {$ENDIF}
  15. UNIT PRN31_;
  16. {$C MOVEABLE DEMANDLOAD DISCARDABLE}
  17. INTERFACE
  18.    USES
  19.      WINTYPES,
  20.      WIN31,
  21.      WOBJECTS,
  22.      COMMDLG,
  23.      PORT_,
  24.      USRWIN_,
  25.      PRINTDLG;
  26.  
  27.    { TPrintout banding flags }
  28.    CONST
  29.      pf_Graphics  = $01;        { Current band only accepts text }
  30.      pf_Text      = $02;        { Current band only accepts graphics }
  31.      pf_Both      = $03;        { Current band accepts both text and
  32.                                graphics }
  33.    TYPE
  34.       pAbortProc = ^TAbortProc;
  35.  
  36.       tBandInfoStruct = RECORD
  37.         fGraphicsFlag: Bool;
  38.         fTextFlag: Bool;
  39.         GraphcisRect: TRect;
  40.       END;
  41.  
  42.  
  43.   TYPE
  44.     PAbortPrintDlg = ^TAbortPrintDlg;
  45.     TAbortPrintDlg = OBJECT (tDlgWindow)
  46.       CONSTRUCTOR
  47.         init(iparent:PWindowsObject; name :pChar; msg:pChar);
  48.  
  49.       DESTRUCTOR
  50.         done;
  51.           virtual;
  52.       PROCEDURE
  53.         setupWindow;
  54.           virtual;
  55.       PROCEDURE
  56.         wmCommand(var msg:TMessage);
  57.           virtual
  58.             wm_First+wm_Command;
  59.  
  60.       PROCEDURE
  61.       destroy;
  62.         virtual;
  63.  
  64.       PROCEDURE
  65.       wmDestroy(var msg :tMessage);
  66.         virtual
  67.           wm_First+wm_Destroy;
  68.     PRIVATE
  69.       _msg :array[0..200] of Char;
  70.     END;
  71.  
  72.  
  73.    TYPE
  74.      Super      = TPort;
  75.      PPrinter = ^TPrinter;
  76.      TPrinter = OBJECT (Super)
  77.  
  78.        printerData :tPrintDlg;
  79.  
  80.  
  81.        CONSTRUCTOR
  82.          init;
  83.        DESTRUCTOR
  84.          done;
  85.            virtual;
  86.  
  87.        FUNCTION
  88.          context:THandle;
  89.            virtual;
  90.  
  91.        FUNCTION
  92.        isPrinter :Boolean;
  93.          virtual;
  94.  
  95.        FUNCTION
  96.        cycle:Boolean;
  97.          virtual;
  98.  
  99.        FUNCTION
  100.        printFlags :Longint;
  101.          virtual;
  102.  
  103.        FUNCTION
  104.        setupTemplate :pChar;
  105.          virtual;
  106.  
  107.        FUNCTION
  108.        optionsTemplate :pChar;
  109.          virtual;
  110.  
  111.        FUNCTION
  112.        abortTemplate :pChar;
  113.          virtual;
  114.  
  115.        FUNCTION
  116.        makeOptionsDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintOptDlg;
  117.          virtual;
  118.  
  119.        FUNCTION
  120.        makeSetupDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintSetupDlg;
  121.          virtual;
  122.  
  123.        FUNCTION
  124.        makeAbortDlg(wnd :pWindowsObject; msg :pChar) :pAbortPrintDlg;
  125.          virtual;
  126.  
  127.        PROCEDURE
  128.        getDevNames(devNames :pDevNames; var driver, device, output :pChar);
  129.  
  130.        FUNCTION
  131.          errors:Boolean;
  132.        FUNCTION
  133.          aborted:Boolean;
  134.        FUNCTION
  135.          errorNo:Integer;
  136.  
  137.        FUNCTION
  138.        calcBandingFlags(var band :tRect; firstBand :Boolean) :Word;
  139.  
  140.  
  141.        FUNCTION
  142.        print(awin: pUsrWin; docName :pChar): Boolean;
  143.          virtual;
  144.  
  145.        PROCEDURE
  146.          startDoc(win:PWindowsObject; docName:pChar);
  147.        PROCEDURE
  148.          endDoc;
  149.        PROCEDURE
  150.          abortDoc;
  151.  
  152.        FUNCTION
  153.          nextBand(var box:tRect) :Boolean;
  154.  
  155.        PROCEDURE
  156.          startPage;
  157.        PROCEDURE
  158.          endPage;
  159.  
  160.        PROCEDURE
  161.          setAbortProc(proc :tAbortProc);
  162.  
  163.        PROCEDURE
  164.          getPageSize(var dim:tPoint);
  165.  
  166.        PROCEDURE
  167.          printingOffset(var off :tPoint);
  168.  
  169.  
  170.        FUNCTION
  171.        banding :Boolean;
  172.  
  173.        FUNCTION
  174.        options(wnd :pUsrWin):Boolean;
  175.  
  176.        PROCEDURE
  177.        setup(wnd :pWindowsObject);
  178.  
  179.      PRIVATE
  180.        _errorNo     :Integer;
  181.        _abortProc   :tFarProc;
  182.        _banding,
  183.        _useBandInfo :Boolean;
  184.      END;{OBJECT TDevice}
  185.  
  186.  
  187.  
  188. IMPLEMENTATION
  189.   USES
  190.     WINPROCS,
  191.     STRINGS;
  192.  
  193.   CONST
  194.     userAbort    :Boolean = TRUE;
  195.     printErrors  :Boolean = FALSE;
  196.     abortDlg     :pWindowsObject = nil;
  197.     id_Msg                = 100;
  198.  
  199.  
  200.   FUNCTION
  201.   {}
  202.   printingAbort(hdc :THandle; code :Integer) :Boolean;
  203.   export;
  204.       var
  205.         msg :TMsg;
  206.       begin
  207.         printErrors := printErrors or (code <> 0);
  208.         while not (userAbort or printErrors)
  209.         and peekMessage(msg, 0, 0, 0, pm_Remove)
  210.         do
  211.           if not application^.processAppMsg(msg)
  212.           then begin
  213.             TranslateMessage(Msg);
  214.             DispatchMessage(Msg);
  215.           end;
  216.         printingAbort := not (userAbort or printErrors)
  217.       end;
  218.  
  219.    CONSTRUCTOR
  220.    TAbortPrintDlg.
  221.      {}
  222.    init(iparent:PWindowsObject; name :pChar; msg:pChar);
  223.      begin
  224.        tDlgWindow.init(iparent, name);
  225.        strCopy(_msg, msg);
  226.      end;
  227.  
  228.  
  229.    PROCEDURE
  230.    TAbortPrintDlg.
  231.      {}
  232.    setupWindow;
  233.      begin
  234.        abortDlg := @self;
  235.        tDlgWindow.setupWindow;
  236.        setDlgItemText(hwindow, id_Msg, _msg);
  237.  
  238.        enableWindow(application^.mainWindow^.hwindow, FALSE);
  239.        show(sw_Normal);
  240.        setFocus(hwindow);
  241.        updateWindow(hwindow);
  242.      end;
  243.  
  244.    DESTRUCTOR
  245.    TAbortPrintDlg.
  246.      {}
  247.    done;
  248.      begin
  249.        abortDlg := nil;
  250.        tDlgWindow.done
  251.      end;
  252.  
  253.  
  254.    PROCEDURE
  255.    TAbortPrintDlg.
  256.      {}
  257.    wmCommand(var msg:TMessage);
  258.      begin
  259.        tDlgWindow.wmCommand(msg);
  260.        userAbort    := TRUE;
  261.      end;
  262.  
  263.  
  264.    PROCEDURE
  265.    TAbortPrintDlg.
  266.      {}
  267.    destroy;
  268.      begin
  269.        with application^.mainWindow^
  270.        do begin
  271.          enableWindow(hwindow, TRUE);
  272.          setFocus(hwindow);
  273.        end;
  274.        tDlgWindow.destroy;
  275.      end;
  276.  
  277.  
  278.    PROCEDURE
  279.    TAbortPrintDlg.
  280.      {}
  281.    wmDestroy(var msg :tMessage);
  282.      begin
  283.        with application^.mainWindow^
  284.        do begin
  285.          enableWindow(hwindow, TRUE);
  286.          setFocus(hwindow);
  287.        end;
  288.        tDlgWindow.wmDestroy(msg)
  289.      end;
  290.  
  291.  
  292.    CONSTRUCTOR
  293.    TPrinter.
  294.      {}
  295.    init;
  296.      var
  297.        esc :Integer;
  298.      begin
  299.        if not Super.init
  300.        then
  301.          fail;
  302.        _errorNo   := 1;
  303.        _abortProc := nil;
  304.        userAbort   := FALSE;
  305.        fillChar(printerData, sizeOf(printerData), 0);
  306.        with printerData
  307.        do begin
  308.          lStructSize   := sizeof(printerData);
  309.          hInstance     := SYSTEM.HInstance;
  310.          flags         := pd_ReturnDC or pd_ReturnDefault;
  311.          nMinPage      := 0;
  312.          nMaxPage      := 0;
  313.        end;
  314.  
  315.        if not COMMDLG.printDlg(printerData)
  316.        then
  317.          fail;
  318.  
  319.        printerData.flags := printFlags;
  320.  
  321.  
  322.        setAbortProc(printingAbort);
  323.        _banding := (getDeviceCaps(context, RasterCaps) and rc_Banding) <> 0;
  324.        esc := WINTYPES.BANDINFO;
  325.        _useBandInfo := escape(context, queryEscSupport, sizeOf(esc), @esc, nil) <> 0;
  326.      end;
  327.  
  328.    DESTRUCTOR
  329.    TPrinter.
  330.      {}
  331.    done;
  332.      begin
  333.        if abortDlg <> nil
  334.        then begin
  335.           dispose(abortDlg, done);
  336.           abortDlg := nil
  337.        end;
  338.        with printerData
  339.        do begin
  340.          deleteDC(context);
  341.          globalFree(hDevMode);
  342.          globalFree(hDevNames)
  343.        end;
  344.        Super.done
  345.      end;
  346.  
  347.    FUNCTION
  348.    TPrinter.
  349.      {}
  350.    context:THandle;
  351.      begin
  352.        context := printerData.hDC
  353.      end;
  354.  
  355.    FUNCTION
  356.    tPrinter.
  357.    {}
  358.    printFlags :Longint;
  359.      begin
  360.        printFlags :=    pd_ReturnDC or
  361.                         pd_UseDevModeCopies or
  362.                         pd_NoSelection or
  363.                         pd_NoPageNums or
  364.                         pd_NoWarning
  365.      end;
  366.  
  367.    PROCEDURE
  368.    TPrinter.
  369.      {}
  370.    getDevNames(devNames :pDevNames; var driver, device, output :pChar);
  371.      var
  372.        str :pChar absolute devNames;
  373.      begin
  374.        with devNames^
  375.        do begin
  376.          driver := str+wDriverOffset;
  377.          device := str+wDeviceOffset;
  378.          output := str+wOutputOffset;
  379.        end
  380.      end;
  381.  
  382.    FUNCTION
  383.    TPrinter.
  384.      {}
  385.    errors:Boolean;
  386.      begin
  387.        errors := (_errorNo <= 0) or printErrors
  388.      end;
  389.  
  390.    FUNCTION
  391.    TPrinter.
  392.      {}
  393.    aborted:Boolean;
  394.      begin
  395.        aborted := userAbort
  396.      end;
  397.  
  398.    FUNCTION
  399.    TPrinter.
  400.      {}
  401.    errorNo :Integer;
  402.      begin
  403.        errorNo := _errorNo
  404.      end;
  405.  
  406.    PROCEDURE
  407.    TPrinter.
  408.      {}
  409.    startDoc(win:PWindowsObject; docName:pChar);
  410.      var
  411.        winDC  :PPort;
  412.        abdlg  :PAbortPrintDlg;
  413.        msg    :array[0..300] of Char;
  414.        devName,
  415.        driver,
  416.        outp   :pChar;
  417.  
  418.        info   :TDocInfo;
  419.  
  420.      begin
  421.        with printerData
  422.        do begin
  423.          getDevNames(globalLock(hDevNames), driver, devName, outp);
  424.          globalUnlock(hDevNames)
  425.        end;
  426.        strPCopy(msg, 'Printing'#10+
  427.                      strPas(docName)+#10+
  428.                      'on'#10+
  429.                      strPas(devName)+#10+
  430.                      'connected to'+#10+
  431.                      strPas(outp)
  432.                      );
  433.        if not errors
  434.        then begin
  435.          abortDlg := application^.makeWindow(makeAbortDlg(win, msg));
  436.          if abortDlg = nil
  437.          then
  438.            exit
  439.        end;
  440.        userAbort   := FALSE;
  441.        printErrors := FALSE;
  442.  
  443.        with info
  444.        do begin
  445.          cbSize := sizeOf(info);
  446.          lpszDocName := docName;
  447.          lpszOutput   := nil
  448.        end;
  449.        _errorNo := WIN31.setAbortProc(context, tAbortProc(_abortProc));
  450.        if not errors
  451.        then
  452.          _errorNo := WIN31.startDoc(context, info)
  453.      end;
  454.  
  455.    PROCEDURE
  456.    TPrinter.
  457.      {}
  458.    endDoc;
  459.      begin
  460.        if not errors
  461.        and not aborted
  462.        then
  463.          _errorNo := WIN31.endDoc(context)
  464.        else
  465.          abortDoc;
  466.        if abortDlg <> nil
  467.        then begin
  468.           dispose(abortDlg, done);
  469.           abortDlg := nil
  470.        end
  471.      end;
  472.  
  473.    PROCEDURE
  474.    TPrinter.
  475.      {}
  476.    abortDoc;
  477.      begin
  478.        userAbort := TRUE;
  479.        _errorNo := WIN31.abortDoc(context);
  480.        if abortDlg <> nil
  481.        then begin
  482.           dispose(abortDlg, done);
  483.           abortDlg := nil
  484.        end;
  485.      end;
  486.  
  487.    FUNCTION
  488.    TPrinter.
  489.      {}
  490.    nextBand(var box:tRect) :Boolean;
  491.      begin
  492.        if banding then
  493.          _errorNo := escape(context, WinTypes.NEXTBAND, 0, nil, @box)
  494.        else
  495.          _errorNo := escape(context, WinTypes.GetPhysPageSize, 0, nil, @box);
  496.        nextBand := not isRectEmpty(box) and not errors and not userAbort
  497.      end;
  498.  
  499.    PROCEDURE
  500.    TPrinter.
  501.      {}
  502.    getPageSize(var dim:tPoint);
  503.      begin
  504.        _errorNo := escape(context, WinTypes.GetPhysPageSize, 0, nil, @dim);
  505.      end;
  506.  
  507.    PROCEDURE
  508.    TPrinter.
  509.      {}
  510.    printingOffset(var off :tPoint);
  511.      begin
  512.        _errorNo := escape(context, WinTypes.GetPrintingOffset, 0, nil, @off);
  513.      end;
  514.  
  515.  
  516.    PROCEDURE
  517.    TPrinter.
  518.      {}
  519.    startPage;
  520.      begin
  521.        _errorNo := WIN31.startPage(context)
  522.      end;
  523.  
  524.    PROCEDURE
  525.    TPrinter.
  526.      {}
  527.    endPage;
  528.      begin
  529.        {_errorNo := }WIN31.endPage(context)
  530.      end;
  531.  
  532.    PROCEDURE
  533.    TPrinter.
  534.      {}
  535.    setAbortProc(proc :tAbortProc);
  536.      begin
  537.        _abortProc := makeProcInstance(@proc, hinstance);
  538.        WIN31.setAbortProc(context, tAbortProc(_abortProc))
  539.      end;
  540.  
  541.    FUNCTION
  542.    tPrinter.
  543.    {}
  544.    isPrinter :Boolean;
  545.      begin
  546.        isPrinter := TRUE
  547.      end;
  548.  
  549.    FUNCTION
  550.    TPrinter.
  551.      {}
  552.    cycle:Boolean;
  553.      begin
  554.          cycle := tAbortProc(_abortProc)(context, 0) and not errors;
  555.      end;
  556.  
  557.    FUNCTION
  558.    TPrinter.
  559.      {}
  560.    banding :Boolean;
  561.      begin
  562.        banding := _banding
  563.      end;
  564.  
  565.    FUNCTION
  566.    tPrinter.
  567.    {}
  568.    setupTemplate :pChar;
  569.      begin
  570.        setupTemplate := nil
  571.      end;
  572.  
  573.    FUNCTION
  574.    tPrinter.
  575.    {}
  576.    optionsTemplate :pChar;
  577.      begin
  578.        optionsTemplate := nil
  579.      end;
  580.  
  581.    FUNCTION
  582.    tPrinter.
  583.    {}
  584.    abortTemplate :pChar;
  585.      begin
  586.        abortTemplate := 'PRINTING_DLG'
  587.      end;
  588.  
  589.    FUNCTION
  590.    tPrinter.
  591.    {}
  592.    makeOptionsDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintOptDlg;
  593.      begin
  594.       makeOptionsDlg :=  new( pPrintOptDlg, init(wnd, optionsTemplate, data, makeSetupDlg(wnd, data)));
  595.      end;
  596.  
  597.    FUNCTION
  598.    tPrinter.
  599.    {}
  600.    makeSetupDlg(wnd :pWindowsObject; data:pPrintDlg) :pPrintSetupDlg;
  601.      begin
  602.       makeSetupDlg :=  new( pPrintSetupDlg,init(wnd, setupTemplate, @printerData));
  603.      end;
  604.  
  605.    FUNCTION
  606.    tPrinter.
  607.    {}
  608.    makeAbortDlg(wnd :pWindowsObject; msg :pChar) :pAbortPrintDlg;
  609.      begin
  610.       makeAbortDlg :=  new( pAbortPrintDlg,init(wnd, abortTemplate, msg));
  611.      end;
  612.  
  613.    FUNCTION
  614.    TPrinter.
  615.      {}
  616.    options(wnd :pUsrWin):Boolean;
  617.      begin
  618.        with printerData
  619.        do begin
  620.          wnd^.getPrintRange(nMinPage, nMaxPage);
  621.          flags := flags or wnd^.printFlags;
  622.          if nMinPage <> nMaxPage
  623.          then
  624.            flags := flags and not pd_NoPageNums
  625.        end;
  626.        options := id_Ok =
  627.        application^.execDialog(makeOptionsDlg(wnd, @printerData))
  628.      end;
  629.  
  630.  
  631.    PROCEDURE
  632.    TPrinter.
  633.      {}
  634.    setup(wnd :pWindowsObject);
  635.      begin
  636.        with printerData
  637.        do
  638.          flags := flags or printFlags;
  639.        application^.execDialog(makeSetupDlg(wnd, @printerData))
  640.      end;
  641.  
  642.    FUNCTION
  643.    tPrinter.
  644.    {}
  645.    calcBandingFlags(var band :tRect; firstBand :Boolean) :Word;
  646.      var
  647.        BandInfoRec  :TBandInfoStruct;
  648.        pFlags       :Word;
  649.        flags        :Word;
  650.        pageSize     :tPoint;
  651.      begin
  652.        { Calculate text verses graphics banding }
  653.        if _useBandInfo
  654.        then begin
  655.          escape(context, bandInfo, sizeOf(tBandInfoStruct), nil, @BandInfoRec);
  656.          if bandInfoRec.fGraphicsFlag
  657.          then
  658.            pFlags := pf_Graphics;
  659.      (*    if BandInfoRec.fTextFlag then pFlags := pf_Text; *)
  660.          if BandInfoRec.fTextFlag
  661.          then pFlags := pFlags or pf_Text;
  662.          flags := (flags and not pf_Both) or pFlags;
  663.        end
  664.        else begin
  665.          { If a driver does not support BandInfo the Microsoft
  666.            Recommended way of determining text only bands is if
  667.            the first band is the full page, all others are
  668.            graphcis only.  Otherwise it handles both. }
  669.          getPageSize(pageSize);
  670.          if firstBand
  671.   {           and (LongInt((@band.left)^) = 0)  %% dunno what this is for}
  672.          and (band.right = PageSize.X)
  673.          and (band.bottom = PageSize.Y)
  674.          then
  675.            flags := pf_Text
  676.          else if Flags
  677.          and pf_Both = pf_Text
  678.          then
  679.            { All other bands are graphics only }
  680.            flags := (Flags and not pf_Both) or pf_Graphics
  681.          else
  682.            flags := flags or pf_Both;
  683.        end;
  684.  
  685.        calcBandingFlags := flags
  686.      end;
  687.  
  688.    FUNCTION
  689.    TPrinter.
  690.    {}
  691.    print(awin: pUsrWin; docName :pChar): Boolean;
  692.      var
  693.        PageSize      :tPoint;
  694.        band          :tRect;
  695.        firstBand     :Boolean;
  696.        flags         :Word;
  697.        pageNumber    :Word;
  698.  
  699.      begin
  700.         if not options(aWin)
  701.         then begin
  702.           print := TRUE;
  703.           exit
  704.         end;
  705.  
  706.         print := False; { Assume error occured }
  707.  
  708.        _errorNo := 0;
  709.  
  710.        if aWin = nil
  711.        then
  712.          exit;
  713.  
  714.        if context = 0
  715.        then
  716.          exit;
  717.  
  718.        { Get the page size }
  719.        getPageSize(pageSize);
  720.  
  721.        if not banding
  722.        then
  723.          with pageSize
  724.          do
  725.            setRect(band, 0, 0, x, y)
  726.        else begin
  727.          { Only use BandInfo if supported (note: using Flags as a temporary) }
  728.          flags := bandInfo;
  729.        end;
  730.  
  731.        flags := pf_Both;
  732.  
  733.        startDoc(aWin, docName);
  734.  
  735.        pageNumber := printerData.nMinPage;
  736.        if not errors
  737.        then begin
  738.          repeat
  739.            startPage;
  740.            if banding
  741.            then begin
  742.              firstBand := TRUE;
  743.              nextBand(band)
  744.            end;
  745.            repeat
  746.              { Call the abort proc between bands or pages }
  747.              cycle;
  748.  
  749.              if banding
  750.              then begin
  751.                flags := calcBandingFlags(band, firstBand);
  752.                if {(Printout^.ForceAllBands)} FALSE and (Flags and pf_Both = pf_Text)
  753.                then
  754.                  setPixel(0, 0, 0);
  755.              end;
  756.  
  757.              if not errors
  758.              then
  759.                aWin^.printPage(@self, pageNumber, pageSize, band, flags);
  760.              firstBand := FALSE
  761.            until
  762.               errors or
  763.               not banding
  764.               or not nextBand(band);
  765.  
  766.            { NewFrame should only be called if not banding }
  767.            if not errors
  768.            then
  769.              endPage;
  770.  
  771.            inc(pageNumber);
  772.          until
  773.            errors    or
  774.            userAbort or
  775.            (pageNumber > printerData.nMaxPage);
  776.  
  777.          { Tell GDI the document is finished }
  778.          endDoc
  779.        end;
  780.  
  781.        print := not errors
  782.      end;
  783.  
  784.  
  785. END.